import Guide from '~/components/layout/guide'
import Snippet from '~/components/snippet'
import { InlineCode } from '~/components/text/code'
import { Image } from '~/components/media'
import Caption from '~/components/text/caption'
import Note from '~/components/text/note'
import Link from '~/components/text/link'
import DeploySection from '~/components/guides/deploy-section'

export const meta = {
  title: 'Create a Next.js App with Contentful and Deploy It with ZEIT Now',
  description:
    'Deploy your Next.js and Contentful app with ZEIT Now in a serverless environment.',
  published: '2019-06-18T16:51:04.000Z',
  authors: ['msweeneydev'],
  url: '/guides/deploying-next-and-contentful-with-now',
  image: `${
    process.env.ASSETS
  }/guides/deploying-next-contentful-with-now/deploying-next-contentful-with-now.png`,
  editUrl: 'pages/guides/deploying-next-and-contentful-with-now.mdx',
  name: 'Next.js + Contentful',
  type: 'app',
  lastEdited: '2020-02-04T12:49:00.000Z'
}

In this guide, you will discover how to create a [Next.js](https://nextjs.org/) app that displays links to posts from the [ZEIT blog](/blog) by utilizing the [Contentful](https://www.contentful.com/) client, before deploying **with a single command** to [ZEIT Now](/docs/v2).

[Next.js](https://nextjs.org/) from [ZEIT](https://zeit.co) is a **production-ready framework** that helps you create fast React apps. [Contentful](https://www.contentful.com/) is a powerful headless CMS that allows you to **rapidly create, manage and distribute content** to any platform you like.

By following this guide, you will create a clone of the [example app](https://nextjs-contentful.now-examples.now.sh/), a starting point to get you up and running with your own Next.js + Contentful app in minutes.

<Image
  src={`${
    process.env.ASSETS
  }/guides/deploying-next-contentful-with-now/deploying-next-contentful-with-now.png`}
  width={2048 / 2.75}
  height={1170 / 2.75}
  oversize
/>

## Step 1: Create your Contentful Content

From your [Contentful Spaces dashboard](https://app.contentful.com/spaces/), create a new **Content Model** called **Post** by clicking the **Add content Type** button.

<Image
  src={`${
    process.env.ASSETS
  }/guides/deploying-next-contentful-with-now/creating-content-model.png`}
  width={1390 / 2}
  height={1130 / 2}
  oversize
  shadow
/>
<Caption>Creating a Content Model for your Next.js + Contentful project using the Contentful dashboard.</Caption>

Add the following fields to your **Content Model**, all of type **Short Text**, by clicking the **Add field** button:

- `title`
- `date`
- `alt`
- `image`
- `url`

Your **Post Content Model** should look like this:

<Image
  src={`${
    process.env.ASSETS
  }/guides/deploying-next-contentful-with-now/completed-content-model.png`}
  width={1564 / 2}
  height={786 / 2}
  oversize
  shadow
/>
<Caption>An example Content Model for your Next.js + Contentful project.</Caption>

Next, using the **Content** tab, click the **Add Post** button to create a post, providing the relevant details.

That's it for creating content! You can edit both the **Content** and **Content Model** at any time, giving you complete flexibility over your content.

Next, you will create a set of API keys for use in your app, this will allow you to connect to the [Contentful Client](https://www.contentful.com/developers/docs/javascript/tutorials/using-js-cda-sdk/) to request your posts.

## Step 2: Creating API keys

Click the **Settings** tab and choose the **API Keys** option, then click the **Add API Key** button.

<Note>Use separate keys for each platform you need to deliver content to.</Note>

With the keys created, make a note of both the **Space ID** and the **Content Delivery API - access token**, these will be used later on.

That's all the setup required for [Contentful](https://www.contentful.com/), within **just a few minutes** you have managed to create a **Content Model**, add content and generate a set of API keys.

In the next step, you will create your [Next.js](https://nextjs.org/) app.

## Step 3: Creating your Next.js App

Firstly, create a project directory and `cd` into it like so:

<Snippet dark text="mkdir my-nextjs-contentful-project && cd my-nextjs-contentful-project" />
<Caption>Creating and entering into the project directory.</Caption>

Next, initialize your project, creating a `package.json` file in the process:

<Snippet dark text="npm init -y" />
<Caption>Initializing your project with a <InlineCode>package.json</InlineCode> file.</Caption>

<Note>
  Using the <InlineCode>-y</InlineCode> flag will initialize the created{' '}
  <InlineCode>package.json</InlineCode> file with{' '}
  <Link href="https://docs.npmjs.com/cli/init">these</Link> default settings.
</Note>

Next, add the project dependencies:

<Snippet dark text="npm i contentful next react react-dom" />
<Caption>Adding <InlineCode>contentful</InlineCode>, <InlineCode>next</InlineCode>, <InlineCode>react</InlineCode> and <InlineCode>react-dom</InlineCode> as dependencies to your project.</Caption>

With the project initialized, create a `/pages` directory with a `index.js` file inside that uses the following code:

```jsx
import { useEffect, useState } from 'react'
import Head from 'next/head'
import Post from '../components/post'

const client = require('contentful').createClient({
  space: process.env.SPACE_ID,
  accessToken: process.env.ACCESS_TOKEN
})

function HomePage() {
  async function fetchEntries() {
    const entries = await client.getEntries()
    if (entries.items) return entries.items
    console.log(`Error getting Entries for ${contentType.name}.`)
  }

  const [posts, setPosts] = useState([])

  useEffect(() => {
    async function getPosts() {
      const allPosts = await fetchEntries()
      setPosts([...allPosts])
    }
    getPosts()
  }, [])

  return (
    <>
      <Head>
        <title>Next.js + Contentful</title>
        <link
          rel="stylesheet"
          href="https://css.zeit.sh/v1.css"
          type="text/css"
        />
      </Head>
      {posts.length > 0
        ? posts.map(p => (
            <Post
              alt={p.fields.alt}
              date={p.fields.date}
              key={p.fields.title}
              image={p.fields.image}
              title={p.fields.title}
              url={p.fields.url}
            />
          ))
        : null}
    </>
  )
}

export default HomePage
```

<Caption>
  An example <InlineCode>index.js</InlineCode> page for your Next.js +
  Contentful project.
</Caption>

Let's take look at what this file achieves.

Firstly, it requires the `contentful` dependency and creates a client, this provides access to many [useful helper methods](https://github.com/contentful/boilerplate-javascript) for retrieving content from [Contentful](https://www.contentful.com/).

Inside the `HomePage` function, two asynchronous functions are defined, these are then called in the `useEffect` hook to retrieve the posts on initial load.

<Note>
  These functions are simplified versions taken from the{' '}
  <Link href="https://github.com/contentful/boilerplate-javascript">
    Contentful JavaScript Boilerplate
  </Link>
  .
</Note>

With the posts retrieved, they are then mapped over to be displayed with a `<Post>` component that you will create next.

Create a `/components` directory that contains a `post.js` file with the following content:

```jsx
function Post({ alt, date, image, title, url }) {
  return (
    <div className="container">
      <a href={url}>
        <img alt={alt} src={image} />
      </a>
      <div className="text">
        <h2>{title}</h2>
        <h4>{date}</h4>
      </div>
      <style jsx>{`
        .container {
          cursor: pointer;
          height: 453px;
          margin-bottom: 48px;
        }
        a {
          border-bottom: none;
        }
        a:hover {
          border-bottom: none;
        }
        .text {
          margin-top: -160px;
          padding: 24px;
          position: absolute;
        }
        h2 {
          color: white;
          font-size: 24px;
          margin-bottom: 0;
        }
        h4 {
          color: rgba(255, 255, 255, 0.8);
          font-size: 16px;
          font-weight: 500;
          margin-top: 8px;
        }
      `}</style>
    </div>
  )
}

export default Post
```

<Caption>
  An example <InlineCode>post.js</InlineCode> component for your Next.js +
  Contentful project.
</Caption>

Now that your page and component files have been created, the next step will show you how to add an [environment variable](/docs/v2/deployments/environment-variables-and-secrets/) to the project.

## Step 4: Adding Environment Variables

Add a `now.json` file at the root of your project directory with the following code:

```json
{
  "build": {
    "env": {
      "CONTENTFUL_SPACE_ID": "@contentful_space_id",
      "CONTENTFUL_ACCESS_TOKEN": "@contentful_access_token"
    }
  }
}
```

<Caption>
  An example <InlineCode>now.json</InlineCode> file for your Next.js +
  Contentful project.
</Caption>

Now, add the following scripts to your `package.json` file:

```json
{
  ...
  "scripts": {
    "dev": "next dev",
    "build": "next build"
  }
}
```

<Caption>
  Adding <InlineCode>dev</InlineCode> and <InlineCode>build</InlineCode> scripts
  to your <InlineCode>package.json</InlineCode> file.
</Caption>

Next, you will make your API keys available to your app during local development by creating a `.env.build` file.

Create a `.env.build` file at the root of your project directory with the following code, adding your API keys where instructed:

```bash
CONTENTFUL_SPACE_ID=your-space-id
CONTENTFUL_ACCESS_TOKEN=your-access-token
```

<Caption>
  An example <InlineCode>.env.build</InlineCode> file for your Next.js +
  Contentful project.
</Caption>

Lastly, to make your API keys available for [cloud deployment](/docs/v2/deployments/basics/), create two [Now Secrets](/docs/v2/deployments/environment-variables-and-secrets#securing-environment-variables-using-secrets) with the commands below:

<Snippet dark text="now secrets add CONTENTFUL_SPACE_ID your-space-id" />
<Caption>
  Adding the <InlineCode>CONTENTFUL_SPACE_ID</InlineCode> secret to your project using <Link href="/docs/v2/deployments/environment-variables-and-secrets#securing-environment-variables-using-secrets">Now Secrets</Link>.
</Caption>

<Snippet dark text="now secrets add CONTENTFUL_ACCESS_TOKEN your-access-token" />
<Caption>
  Adding the <InlineCode>CONTENTFUL_ACCESS_TOKEN</InlineCode> secret to your project using <Link href="/docs/v2/deployments/environment-variables-and-secrets#securing-environment-variables-using-secrets">Now Secrets</Link>.
</Caption>

With those steps out the way you are now able to run your app. You can develop your app locally using the following command:

<Snippet dark text="now dev" />
<Caption>
  Using the <InlineCode>now dev</InlineCode> command to run the app locally.
</Caption>

## Step 5: Deploying the App

<DeploySection meta={meta} />

export default ({ children }) => <Guide meta={meta}>{children}</Guide>

export const config = {
  amp: 'hybrid'
}
